#include "audio.h"
#include "audio_set.h"
#include "script/scripthelper.h"
#include "vfs/vfs.h"
#include "script/scripthelper.h"

#include "ui/ui_manager.h"
#include "util/log.h"				// log
#include "util/common_macros.h"		// macros
#include "util/mmgr.h"		    

#ifdef _ENABLE_LUABIND
#include <luabind/luabind.hpp>
#endif //_ENABLE_LUABIND

using namespace audio;
using namespace script;

Audio::Audio() :
	m_CurrentMusic(0),
	m_pAudioSet(0),
	m_SFXVolume(70),
	m_MusicVolume(70),
	m_MusicBias(1.0f),
	m_AudioBias(0.6f),
	m_IsInit(false)
{
}

Audio::~Audio()
{
	UTIL_SAFE_DELETE(m_pAudioSet);
}

void		Audio::LoadAudioSet(const std::string& AudioSetFile)
{
	if (AudioSetFile.empty()) return;
	m_pAudioSet = new AudioSet();
	m_pAudioSet->Load(AudioSetFile);
}

void		Audio::Init(const std::string& AudioSetFile)
{
	m_IsInit = true;

	LoadAudioSet(AudioSetFile);
#if  defined(_PLATFORM_IOS) || defined(_PLATFORM_ANDROID)
#else
	LoadSegments("sounds/segments.lua");
#endif
}


AudioHandle		Audio::PlayEvent(const std::string& Name, float AudioBias)
{
	if (!m_IsInit) return NULL;

	// does it exist in the sound-bank?
	AudioHandle Handle = NULL;
	if (m_pAudioSet)
	{
		Handle = m_pAudioSet->PlayEffect(Name);
	}
	if (Handle && Handle != -1) return Handle;

	// load and play it as a throwaway sound?
#ifndef _PLATFORM_WII
	AudioFile	Sound = LoadSound(Name, false);
	if (Sound)
	{
		return PlaySFX(Sound, AudioBias);		
	}
#endif // _PLATFORM_WII
	return NULL;
}

AudioFile	Audio::LoadSound(const std::string& Name, bool Repeat)
{
	if (!m_IsInit) return 0;

	Sample*	pSample = m_Samples.GetElement(Name);
	if (pSample) return pSample->Handle;

	if (BrokenSamples*	pMissing = m_Broken.GetElement(Name)) return NULL;
	
	vfs::LoadedBlock	Data;
	if (vfs::VFS::Instance().GetFile(Name, Data))
	{
		AudioFile Res = LoadSoundFromMemory(Data,Repeat);
		if (Res == 0)
		{
			BrokenSamples*	pMissing = new BrokenSamples;
			m_Broken.AddElement(Name, pMissing);
		}
		else
		{
			ui::UIManager::Instance().UpdateLoadCB();
		}
		return Res;
	}  else
	{
		BrokenSamples*	pMissing = new BrokenSamples;
		m_Broken.AddElement(Name, pMissing);
	}
	return 0;
}

void		Audio::LoadSegments(const std::string& File)
{
	if (!m_IsInit) return;

	LuaPlus::LuaState*	pScript = ScriptHelper::CreateLuaState();
	if (!ScriptHelper::DoFile(*pScript, File))
	{
		_LOG(MSG_ERROR, "Unable to load audio segment file " << File << "!");
		 LuaPlus::LuaState::Destroy( pScript );
		return;
	} else
	{
		LuaPlus::LuaObject	Segments = ScriptHelper::GetObj(*pScript, "AudioSegments");
		if (Segments.IsTable())
		{
			for (int i=0; i<Segments.GetTableCount(); i++)
			{
				LuaPlus::LuaObject	Segment = Segments[i+1];
				if (Segment.IsTable())
				{
					MusicSegments* pSegment = new MusicSegments;
					pSegment->Name = script::ScriptHelper::GetTableString(Segment, "Name");
					pSegment->MusicFile = script::ScriptHelper::GetTableString(Segment, "File");
					pSegment->Bias = script::ScriptHelper::GetTableFloat(Segment, "Bias", 1);
					pSegment->Order = script::ScriptHelper::GetTableInt(Segment, "Order", 0);
					pSegment->Row   = script::ScriptHelper::GetTableInt(Segment, "Row", 0);
					m_Segments.AddElement(pSegment->Name, pSegment);
				}
			}
		}
	}
	LuaPlus::LuaState::Destroy( pScript );
}

void		Audio::PlaySegment(const std::string& Name)
{
	if (!m_IsInit) return;

	if (strcmpi(Name.c_str(), m_CurrentSegment.c_str())==0) return;
	MusicSegments* pSegment  = m_Segments.GetElement(Name);
	if (!pSegment) return;

	AudioHandle	Music = PlayMusic(pSegment->MusicFile, pSegment->Bias);
	if (Music)
	{
		m_CurrentSegment = Name;
	}
}

void		Audio::StopAll()
{
	if (!m_IsInit) return;

	StopMusic();
}
void		Audio::GetAudioInfo(unsigned int& Files, unsigned int& Memory)
{
	Files = 0;
	Memory = 0;
	for (unsigned int i=0; i<m_pAudioSet->GetElementC(); i++)
	{
		AudioSubset* pSet = m_pAudioSet->GetElementByIndex(i);
		for (unsigned int j=0; j<pSet->AudioFiles.size(); j++)
		{
			Files++;
			Memory += pSet->AudioFiles[j].Size;
		}
	}
	Memory/=1024;
}

void		Audio::Register(LuaPlus::LuaState* _pScript)
{
#ifdef _ENABLE_LUABIND
    lua_State * L = _pScript->GetCState ( );

	luabind::module(L)
    [

    luabind::class_< Audio >( "Audio" )
//        .def( "PlayEffect",		PlayEffect)
		.def( "PlaySoundEvent",	&Audio::PlayEvent )
		.def( "PlayMusic",		&Audio::PlayMusic)
        .def( "StopSound",		&Audio::StopSound)
		.def( "StopAll",		&Audio::StopAll)
		.def( "PlaySound",		&Audio::PlayEvent)
		.def( "SetSFXVolume", 	&Audio::SetSFXVolume)
		.def( "SetMusicVolume", &Audio::SetMusicVolume)
		.def( "GetSFXVolume", 	&Audio::GetSFXVolume)
		.def( "GetMusicVolume", &Audio::GetMusicVolume)
		.def( "PlaySegment",	&Audio::PlaySegment)

    ];
	
	// Access file from config
//	luabind::module(L)
//    [	 luabind::def("GetAudio",     &Audio::Instance,  luabind::detail::null_type() )		];
#endif //_ENABLE_LUABIND

}